/******************************************************************
*
* CyberHTTP for Java
*
* Copyright (C) Satoshi Konno 2002-2003
*
* File: HTTPResponse.java
*
* Revision;
*
* 11/18/02
*   - first revision.
* 10/22/03
*   - Changed to initialize a content length header.
* 
******************************************************************/

package com.cidero.http;

import java.io.*;
import java.util.logging.Logger;

import com.cidero.util.BufferedReaderInputStream;

public class HTTPResponse extends HTTPPacket
{
  private static Logger logger = Logger.getLogger("com.cidero.http");

  private HTTPConnection connection;  // Current open connection 
  private HTTPStatus     httpStatus = new HTTPStatus();
  
  /**
   *  Default constructor. Used by server side to instantiate an
   *  outgoing response object.
   */
  public HTTPResponse()
  {
    // setContentType(HTML.CONTENT_TYPE);
    setServer(HTTPServer.getName());
    setPacketContent("");
  }

  /**
   * Construct an HTTPResponse object from an HTTP connection. Used by
   * the client side to instantiate an incoming response object
   *
   * @param  connection   
   *           Connection to read incoming response from
   */ 
  public HTTPResponse( HTTPConnection connection )
    throws IOException
  {
    this( connection, true );
  }

  /**
   * Construct an HTTPResponse object from an HTTP connection. Used by
   * the client side to instantiate an incoming response object
   * A flag controls whether the content is read, or only the header
   * (useful in streaming data situations)
   *
   * @param  connection   
   *           Connection to read incoming response from
   *
   * @param  getContent
   *           If true, then retrieve content from connection. If
   *           false, just read the header.
   */ 
  public HTTPResponse( HTTPConnection connection, boolean getContent )
    throws IOException
  {
    logger.fine("Entered: ");

    this.connection = connection;

    BufferedReaderInputStream inputStream = connection.getInputStream();
    
    logger.fine("Reading 1st line: ");
    String firstLine = inputStream.readLine();
    setFirstLine( firstLine );
      
    logger.fine("First line: " + firstLine );
    
    httpStatus = new HTTPStatus( firstLine );
    int statusCode = httpStatus.getStatusCode();

    // Ignore 100 - CONTINUE response if present 
    if (statusCode == HTTPStatus.CONTINUE)
    {
      //skip all header lines in CONTINUE response
      readHeaderLines( inputStream );
      
      //look forward another first line
      String actualFirstLine = inputStream.readLine();
      if ((actualFirstLine != null) && (actualFirstLine.length() > 0) )
      {
        //this is the actual first line
        setFirstLine(actualFirstLine);
      }
      else
      {
        throw new IOException("Error reading response after receipt of HTTP Continue (100)");
      }
    }
      
    httpStatus = new HTTPStatus( getFirstLine() );
    readHeaderLines( inputStream );

    statusCode = httpStatus.getStatusCode();

    if( (statusCode == HTTPStatus.MOVED_PERMANENTLY) || 
        (statusCode == HTTPStatus.FOUND) ||   // temporarily moved
        (statusCode == HTTPStatus.SEE_OTHER) ||
        (statusCode == HTTPStatus.USE_PROXY) ||
        (statusCode == HTTPStatus.TEMPORARY_REDIRECT) )
    {
      readContent( connection.getInputStream() );

      logger.info("status = " + statusCode + " redirecting URL, content of redirect is:\n" +
                  getContentString() );
    
    }
  }

  /**
   *  Return the response content. If the response body has not yet
   *  been read from the HTTP connection, the read is performed.
   *
   *  @return HTTP response content byte array, or null if there is
   *          no content associated with response
   */
  public byte[] getContent() throws IOException
  {
    // If content already retrieved, return it
    if( getPacketContent() != null )  
      return getPacketContent(); 
    
    readContent( connection.getInputStream() );
    return getPacketContent(); 
  }

  public String getContentString() throws IOException
  {
    return new String( getContent() );
  }
  
  public void setStatusCode(int code)
  {
    httpStatus.setStatusCode(code);
  }
  public int getStatusCode()
  {
    return httpStatus.getStatusCode();
  }

  public InputStream getInputStream()
  {
    return connection.getInputStream();
  }

  public void releaseConnection()
  {
    connection.release();
  }

  public String getStatusLineString()
  {
    return "HTTP/" + HTTP.VERSION + " " + getStatusCode() + " " + 
      HTTPStatus.code2String( getStatusCode() ) + HTTP.CRLF;
  }
  
  /**
   *  Return header portion of HTTP response as ASCII string. Include
   *  the trailing <CR><LF> pair
   *
   *  @return   HTTP request header block ( "HTTP/1.0 200 OK" )
   */
  public String getHeaderString()
  {
    StringBuffer str = new StringBuffer();
  
    str.append( getStatusLineString() );
    str.append( getAllHeaderLinesAsString() );
    str.append( HTTP.CRLF );    
    return str.toString();
  }

}

